package redigo

import (
	"fmt"
	"testing"
	"time"

	"github.com/gomodule/redigo/redis"
)

type RedisClient struct {
	Pool        *redis.Pool   `comment:"连接池" json:"pool"`
	RedisHost   string        `comment:"连接地址" json:"redis_host"`
	RedisDb     int           `comment:"数据库" json:"redis_db"`
	MaxIdle     int           `comment:"最大空闲连接数" json:"max_idle"`
	MaxActive   int           `comment:"最大连接数" json:"max_active"`
	IdleTimeout time.Duration `comment:"超时时间" json:"idle_timeout"`
	Password    string        `comment:"redis密码" json:"password"`
}

var RedisPool = &RedisClient{
	Pool:        nil,
	RedisHost:   "127.0.0.1:6379",
	RedisDb:     2,
	MaxIdle:     6,
	MaxActive:   8,
	IdleTimeout: 180,
	Password:    "",
}

func init() {
	RedisPool.Pool = &redis.Pool{
		Dial: func() (redis.Conn, error) {
			c, err := redis.Dial("tcp", RedisPool.RedisHost)
			if err != nil {
				return nil, err
			}
			//验证redis密码
			if RedisPool.Password != "" {
				if _, authErr := c.Do("AUTH", RedisPool.Password); authErr != nil {
					return nil, fmt.Errorf("redis auth password error: %s", authErr)
				}
			}
			// 选择db
			c.Do("SELECT", RedisPool.RedisDb)
			return c, nil
		},
		MaxActive:   RedisPool.MaxActive,
		MaxIdle:     RedisPool.MaxIdle,
		IdleTimeout: RedisPool.IdleTimeout,
	}

	// 重启刷新数据库
	flushDb()

}

// redis 命令执行框架
func RedisExcute(exe func(data interface{}, cnn *redis.Conn), data interface{}) {
	defer func() {
		if err := recover(); err != nil {
			fmt.Printf("-->> redis execute error, the message is : %v  \n", err)
		}
	}()
	c := RedisPool.Pool.Get()
	defer c.Close()
	exe(data, &c)
}

// SetNxStr 唯一值插入
func SetNxStr(key, data interface{}, cnn *redis.Conn) (ok bool) {
	_, err := (*cnn).Do("SETNX", key, data)
	if err != nil {
		fmt.Println("=====> ", err.Error())
	}
	ok = true
	return
}

// SetNxStrWithExpire 带有过期时间的唯一值插入, 常用于分布式锁
func SetNxStrWithExpire(key, data interface{}, expire int, cnn *redis.Conn) (ok bool) {
	_, err := (*cnn).Do("SET", key, fmt.Sprintf(" %v ex %v nx", data, expire))
	if err != nil {
		fmt.Println("=====> ", err.Error())
	}
	ok = true
	return
}

// SetStr 常规存入值, 若存在则覆盖
func SetStr(key, data interface{}, cnn *redis.Conn) (ok bool) {
	//key = strings.TrimSpace(key) + "."
	_, err := (*cnn).Do("SET", key, data)
	if err != nil {
		fmt.Println("=====> ", err.Error())
	}
	ok = true
	return
}

func Get(key string, cnn *redis.Conn) (value string, err error) {
	return redis.String((*cnn).Do("GET", key))
}

func RedisGetAndDel(key string, cnn *redis.Conn) (value string, ok bool) {
	ok = true
	v, err := redis.String((*cnn).Do("GET", key))
	if err != nil {
		fmt.Println("=====> redis get key err : ", err.Error())
		ok = false
	}
	dres, errDel := (*cnn).Do("DEL", key)
	if errDel != nil {
		fmt.Println("=====> redis del key err : ", errDel.Error())
	}
	if dres.(int64) > 0 {
		fmt.Println("=====> redis del sucess")
	} else {
		fmt.Println("=====> redis del sucess")
	}

	value = v
	return
}

func Del(key string, cnn *redis.Conn) (ok bool) {
	ok = true
	dres, errDel := (*cnn).Do("DEL", key)
	if errDel != nil {
		fmt.Println("=====> redis del key err : ", errDel.Error())
	}
	if dres.(int64) > 0 {
		ok = true
		fmt.Println("=====> redis del sucess")
	} else {
		fmt.Println("=====> redis del error")
	}
	return
}

func set_get(data interface{}, cnn *redis.Conn) {
	v, err := (*cnn).Do("SET", "name", "red")
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(v)
	v, err = redis.String((*cnn).Do("GET", "name"))
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(v)
}

func list(data interface{}, cnn *redis.Conn) {
	v, err := (*cnn).Do("lpush", "redlist", "qqq")
	if err != nil {
		fmt.Println(err)
		return
	}
	v, err = (*cnn).Do("lpush", "redlist", "www")
	if err != nil {
		fmt.Println(err)
		return
	}
	v, err = (*cnn).Do("lpush", "redlist", "eee")
	if err != nil {
		fmt.Println(err)
		return
	}
	v, err = (*cnn).Do("lpush", "redlist", "rrr")
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println("=====> ", v)

	values, _ := redis.Values((*cnn).Do("lrange", "redlist", "0", "100"))

	for _, v := range values {
		fmt.Println(string(v.([]byte)))
	}
}

func flushDb() {
	cnn := RedisPool.Pool.Get()
	defer cnn.Close()
	_, err := (cnn).Do("flushdb")
	if err != nil {
		fmt.Println(err)
		return
	}
}

func Test_do(t *testing.T) {
	fmt.Println("testing")
	RedisExcute(func(data interface{}, cnn *redis.Conn) {
		// 设值取值
		//set_get(data, cnn)
		// list
		list(data, cnn)

	}, nil)
}

func parseStr(data interface{}) (res string, ok bool) {
	defer func() {
		if err := recover(); err != nil {
			fmt.Printf("-->>  error, the message is : %v  \n", err)
			ok = false
		}
	}()
	ok = true
	fmt.Println("=====> the data is :", data)

	res = data.(string)
	return
}
